package decoder

/*
   #include "ffmpeg.h"
   int wrap_avcodec_send_packet(AVCodecContext *ctx, void *data, int size) {
   	struct AVPacket pkt = {.data = data, .size = size};
   	return avcodec_send_packet(ctx, &pkt);
   }

   int wrap_swr_convert(struct SwrContext *avr, int *out, int outcount, int *in, int incount) {
   	return swr_convert(avr, (void *)out, outcount, (void *)in, incount);
   }
*/
import "C"
import (
	"fmt"
	"runtime"
	"time"
	"unsafe"
	"xmediaEmu/pkg/decoder/codec"
	"xmediaEmu/pkg/decoder/codec/aacparser"
)

type Resampler struct {
	inSampleFormat, OutSampleFormat   codec.SampleFormat
	inChannelLayout, OutChannelLayout codec.ChannelLayout
	inSampleRate, OutSampleRate       int
	avr                               *C.struct_SwrContext // struct结构体转换.
}

const debug = false

// 音频重采样，转码必备.
func (self *Resampler) Resample(in codec.AudioFrame) (out codec.AudioFrame, err error) {
	// 格式参数.
	formatChange := in.SampleRate != self.inSampleRate || in.SampleFormat != self.inSampleFormat || in.ChannelLayout != self.inChannelLayout

	var flush codec.AudioFrame
	// 采样有变化.
	if formatChange {
		// 清理avr之前未处理完的数据.
		if self.avr != nil {
			outChannels := self.OutChannelLayout.Count()
			if !self.OutSampleFormat.IsPlanar() { // 单极性.
				outChannels = 1
			}

			// 结果缓存，指针数组类型.
			outData := make([]*C.uint8_t, outChannels)
			outSampleCount := int(C.swr_get_out_samples(self.avr, C.int(in.SampleCount)))
			outLinesize := outSampleCount * self.OutSampleFormat.BytesPerSample()
			flush.Data = make([][]byte, outChannels)
			for i := 0; i < outChannels; i++ {
				flush.Data[i] = make([]byte, outLinesize)
				outData[i] = (*C.uint8_t)(unsafe.Pointer(&flush.Data[i][0]))
			}
			flush.ChannelLayout = self.OutChannelLayout
			flush.SampleFormat = self.OutSampleFormat
			flush.SampleRate = self.OutSampleRate

			// 直接c函数调用.
			convertSamples := int(C.wrap_swr_convert(
				self.avr,
				(*C.int)(unsafe.Pointer(&outData[0])), C.int(outSampleCount), // C.int(outLinesize),
				nil, C.int(0),
			))
			if convertSamples < 0 {
				err = fmt.Errorf("ffmpeg: swr_convert failed")
				return
			}
			flush.SampleCount = convertSamples

			// TODO： 直接丢弃？.
			if convertSamples < outSampleCount { // 未转换的其余数据.
				for i := 0; i < outChannels; i++ { // 没啥用，
					flush.Data[i] = flush.Data[i][:convertSamples*self.OutSampleFormat.BytesPerSample()]
				}
			}

			// flush 打印.
			// fmt.Println("flush:", "outSampleCount", outSampleCount, "convertSamples", convertSamples, "datasize", len(flush.Data[0]))

		} else {
			// 最后close
			runtime.SetFinalizer(self, func(self *Resampler) {
				self.Close()
			})
		}

		// 为空释放？...
		C.swr_free(&self.avr)
		self.inSampleFormat = in.SampleFormat
		self.inSampleRate = in.SampleRate
		self.inChannelLayout = in.ChannelLayout
		avr := C.swr_alloc()
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_channel_layout"), C.int64_t(channelLayoutAV2FF(self.inChannelLayout)), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_channel_layout"), C.int64_t(channelLayoutAV2FF(self.OutChannelLayout)), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_sample_rate"), C.int64_t(self.inSampleRate), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_sample_rate"), C.int64_t(self.OutSampleRate), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_sample_fmt"), C.int64_t(sampleFormatAV2FF(self.inSampleFormat)), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_sample_fmt"), C.int64_t(sampleFormatAV2FF(self.OutSampleFormat)), 0)
		C.swr_init(avr)
		self.avr = avr
	}

	// 现有数据转换.
	var inChannels int // , inLinesize int
	inSampleCount := in.SampleCount
	if !self.inSampleFormat.IsPlanar() {
		inChannels = 1
		// inLinesize = inSampleCount * in.SampleFormat.BytesPerSample() * self.inChannelLayout.Count()
	} else {
		inChannels = self.inChannelLayout.Count()
		// inLinesize = inSampleCount * in.SampleFormat.BytesPerSample()
	}
	inData := make([]*C.uint8_t, inChannels)
	for i := 0; i < inChannels; i++ {
		inData[i] = (*C.uint8_t)(unsafe.Pointer(&in.Data[i][0]))
	}

	var outChannels, outLinesize, outBytesPerSample int
	outSampleCount := int(C.swr_get_out_samples(self.avr, C.int(in.SampleCount)))
	if !self.OutSampleFormat.IsPlanar() {
		outChannels = 1
		outBytesPerSample = self.OutSampleFormat.BytesPerSample() * self.OutChannelLayout.Count()
		outLinesize = outSampleCount * outBytesPerSample
	} else {
		outChannels = self.OutChannelLayout.Count()
		outBytesPerSample = self.OutSampleFormat.BytesPerSample()
		outLinesize = outSampleCount * outBytesPerSample
	}
	outData := make([]*C.uint8_t, outChannels)
	out.Data = make([][]byte, outChannels)
	for i := 0; i < outChannels; i++ {
		out.Data[i] = make([]byte, outLinesize)
		outData[i] = (*C.uint8_t)(unsafe.Pointer(&out.Data[i][0]))
	}
	out.ChannelLayout = self.OutChannelLayout
	out.SampleFormat = self.OutSampleFormat
	out.SampleRate = self.OutSampleRate

	convertSamples := int(C.wrap_swr_convert(
		self.avr,
		(*C.int)(unsafe.Pointer(&outData[0])), C.int(outSampleCount), // C.int(outLinesize),
		(*C.int)(unsafe.Pointer(&inData[0])), C.int(inSampleCount),
	))
	if convertSamples < 0 {
		err = fmt.Errorf("ffmpeg: swr_convert failed")
		return
	}

	out.SampleCount = convertSamples
	if convertSamples < outSampleCount {
		for i := 0; i < outChannels; i++ {
			out.Data[i] = out.Data[i][:convertSamples*outBytesPerSample]
		}
	}

	if flush.SampleCount > 0 {
		out = flush.Concat(out)
	}
	return
}

func (self *Resampler) Close() {
	C.swr_free(&self.avr)
}

// AudioEncoder TODO: encoder.
type AudioEncoder struct {
	ff               *ffctx
	SampleRate       int
	Bitrate          int
	ChannelLayout    codec.ChannelLayout
	SampleFormat     codec.SampleFormat
	FrameSampleCount int
	framebuf         codec.AudioFrame
	codecData        codec.AudioCodecData
	resampler        *Resampler
}

func (self *AudioEncoder) SetSampleFormat(fmt codec.SampleFormat) (err error) {
	self.SampleFormat = fmt
	return
}

func (self *AudioEncoder) SetSampleRate(rate int) (err error) {
	self.SampleRate = rate
	return
}

func (self *AudioEncoder) SetChannelLayout(ch codec.ChannelLayout) (err error) {
	self.ChannelLayout = ch
	return
}

func (self *AudioEncoder) SetBitrate(bitrate int) (err error) {
	self.Bitrate = bitrate
	return
}

func (self *AudioEncoder) SetOption(key string, val interface{}) (err error) {
	ff := &self.ff.ff

	sval := fmt.Sprint(val)
	if key == "profile" {
		ff.profile = C.avcodec_profile_name_to_int(ff.codec, C.CString(sval))
		if ff.profile == C.FF_PROFILE_UNKNOWN {
			err = fmt.Errorf("ffmpeg: profile `%s` invalid", sval)
			return
		}
		return
	}

	C.av_dict_set(&ff.options, C.CString(key), C.CString(sval), 0)
	return
}

func (self *AudioEncoder) GetOption(key string, val interface{}) (err error) {
	ff := &self.ff.ff
	entry := C.av_dict_get(ff.options, C.CString(key), nil, 0)
	if entry == nil {
		err = fmt.Errorf("ffmpeg: GetOption failed: `%s` not exists", key)
		return
	}
	switch p := val.(type) {
	case *string:
		*p = C.GoString(entry.value)
	case *int:
		fmt.Sscanf(C.GoString(entry.value), "%d", p)
	default:
		err = fmt.Errorf("ffmpeg: GetOption failed: val must be *string or *int receiver")
		return
	}
	return
}

func (self *AudioEncoder) Setup() (err error) {
	ff := &self.ff.ff

	ff.frame = C.av_frame_alloc()

	if self.SampleFormat == codec.SampleFormat(0) {
		self.SampleFormat = sampleFormatFF2AV(*ff.codec.sample_fmts)
	}

	//if self.Bitrate == 0 {
	//	self.Bitrate = 80000
	//}
	if self.SampleRate == 0 {
		self.SampleRate = 44100
	}
	if self.ChannelLayout == codec.ChannelLayout(0) {
		self.ChannelLayout = codec.CH_STEREO
	}

	ff.codecCtx.sample_fmt = sampleFormatAV2FF(self.SampleFormat)
	ff.codecCtx.sample_rate = C.int(self.SampleRate)
	ff.codecCtx.bit_rate = C.int64_t(self.Bitrate)
	ff.codecCtx.channel_layout = channelLayoutAV2FF(self.ChannelLayout)
	ff.codecCtx.strict_std_compliance = C.FF_COMPLIANCE_EXPERIMENTAL
	ff.codecCtx.flags = C.AV_CODEC_FLAG_GLOBAL_HEADER
	ff.codecCtx.profile = ff.profile

	if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 {
		err = fmt.Errorf("ffmpeg: encoder: avcodec_open2 failed")
		return
	}
	self.SampleFormat = sampleFormatFF2AV(ff.codecCtx.sample_fmt)
	self.FrameSampleCount = int(ff.codecCtx.frame_size)

	extradata := C.GoBytes(unsafe.Pointer(ff.codecCtx.extradata), ff.codecCtx.extradata_size)

	switch ff.codecCtx.codec_id {
	case C.AV_CODEC_ID_AAC:
		if self.codecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(extradata); err != nil {
			return
		}

	default:
		self.codecData = audioCodecData{
			channelLayout: self.ChannelLayout,
			sampleFormat:  self.SampleFormat,
			sampleRate:    self.SampleRate,
			codecId:       ff.codecCtx.codec_id,
			extradata:     extradata,
		}
	}

	return
}

func (self *AudioEncoder) prepare() (err error) {
	ff := &self.ff.ff

	if ff.frame == nil {
		if err = self.Setup(); err != nil {
			return
		}
	}

	return
}

func (self *AudioEncoder) CodecData() (codec codec.AudioCodecData, err error) {
	if err = self.prepare(); err != nil {
		return
	}
	codec = self.codecData
	return
}

func (self *AudioEncoder) encodeOne(frame codec.AudioFrame) (gotpkt bool, pkt []byte, err error) {
	if err = self.prepare(); err != nil {
		return
	}

	ff := &self.ff.ff

	cpkt := C.AVPacket{}
	cgotpkt := C.int(0)
	audioFrameAssignToFF(frame, ff.frame)

	if false {
		farr := []string{}
		for i := 0; i < len(frame.Data[0])/4; i++ {
			var f *float64 = (*float64)(unsafe.Pointer(&frame.Data[0][i*4]))
			farr = append(farr, fmt.Sprintf("%.8f", *f))
		}
		fmt.Println(farr)
	}
	cerr := C.avcodec_encode_audio2(ff.codecCtx, &cpkt, ff.frame, &cgotpkt)
	if cerr < C.int(0) {
		err = fmt.Errorf("ffmpeg: avcodec_encode_audio2 failed: %d", cerr)
		return
	}

	if cgotpkt != 0 {
		gotpkt = true
		pkt = C.GoBytes(unsafe.Pointer(cpkt.data), cpkt.size)
		C.av_packet_unref(&cpkt)

		if debug {
			fmt.Println("ffmpeg: Encode", frame.SampleCount, frame.SampleRate, frame.ChannelLayout, frame.SampleFormat, "len", len(pkt))
		}
	}

	return
}

func (self *AudioEncoder) resample(in codec.AudioFrame) (out codec.AudioFrame, err error) {
	if self.resampler == nil {
		self.resampler = &Resampler{
			OutSampleFormat:  self.SampleFormat,
			OutSampleRate:    self.SampleRate,
			OutChannelLayout: self.ChannelLayout,
		}
	}
	if out, err = self.resampler.Resample(in); err != nil {
		return
	}
	return
}

func (self *AudioEncoder) Encode(frame codec.AudioFrame) (pkts [][]byte, err error) {
	var gotpkt bool
	var pkt []byte

	if frame.SampleFormat != self.SampleFormat || frame.ChannelLayout != self.ChannelLayout || frame.SampleRate != self.SampleRate {
		if frame, err = self.resample(frame); err != nil {
			return
		}
	}

	if self.FrameSampleCount != 0 {
		if self.framebuf.SampleCount == 0 {
			self.framebuf = frame
		} else {
			self.framebuf = self.framebuf.Concat(frame)
		}
		for self.framebuf.SampleCount >= self.FrameSampleCount {
			frame := self.framebuf.Slice(0, self.FrameSampleCount)
			if gotpkt, pkt, err = self.encodeOne(frame); err != nil {
				return
			}
			if gotpkt {
				pkts = append(pkts, pkt)
			}
			self.framebuf = self.framebuf.Slice(self.FrameSampleCount, self.framebuf.SampleCount)
		}
	} else {
		if gotpkt, pkt, err = self.encodeOne(frame); err != nil {
			return
		}
		if gotpkt {
			pkts = append(pkts, pkt)
		}
	}

	return
}

func (self *AudioEncoder) Close() {
	freeFFCtx(self.ff)
	if self.resampler != nil {
		self.resampler.Close()
		self.resampler = nil
	}
}

// AudioDecoder decoder, to pcm 即可.
type AudioDecoder struct {
	Bitrate       int
	ff            *ffctx
	ChannelLayout codec.ChannelLayout
	SampleFormat  codec.SampleFormat
	SampleRate    int
	Extradata     []byte
}

// 初始化.
func (self *AudioDecoder) Setup() (err error) {
	ff := &self.ff.ff
	ff.frame = C.av_frame_alloc()
	if len(self.Extradata) > 0 { // extra data
		ff.codecCtx.extradata = (*C.uint8_t)(unsafe.Pointer(&self.Extradata[0]))
		ff.codecCtx.extradata_size = C.int(len(self.Extradata))

		fmt.Println("ffmpeg: Decoder.Setup Extradata.len", len(self.Extradata))
	}

	ff.codecCtx.bit_rate = C.int64_t(self.Bitrate)
	ff.codecCtx.sample_rate = C.int(self.SampleRate)
	ff.codecCtx.channel_layout = channelLayoutAV2FF(self.ChannelLayout)
	ff.codecCtx.channels = C.int(self.ChannelLayout.Count())
	if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 {
		err = fmt.Errorf("ffmpeg: decoder: avcodec_open2 failed")
		return
	}

	// 写入编码器参数.
	self.SampleFormat = sampleFormatFF2AV(ff.codecCtx.sample_fmt)
	self.ChannelLayout = channelLayoutFF2AV(ff.codecCtx.channel_layout)
	if self.SampleRate == 0 {
		self.SampleRate = int(ff.codecCtx.sample_rate)
	}

	// 设置立即返回.
	//cerr := C.av_opt_set(ff.codecCtx.priv_data, C.CString("tune"), C.CString("zerolatency"), C.int(0))
	//if cerr < 0 {
	//	err = fmt.Errorf("ffmpeg: decoder: av_opt_set failed:%d ", int(cerr))
	//	return
	//}
	return
}

// 对传入的媒体流packet进行解码.
// 语音帧一帧或几帧.
// amr只支持一帧, 否则要自己进行多帧处理.
func (self *AudioDecoder) Decode(pkt []byte) (gotframe bool, frame codec.AudioFrame, err error) {
	ff := &self.ff.ff
	// cgotframe := C.int(0)

	// 解码.
	// Use avcodec_send_packet() and avcodec_receive_frame()..
	cerr := C.wrap_avcodec_send_packet(ff.codecCtx, unsafe.Pointer(&pkt[0]), C.int(len(pkt)))
	if cerr < C.int(0) {
		if cerr == AVERROR_EOF2 {
			gotframe = true
		}
		err = fmt.Errorf("ffmpeg: wrap_avcodec_send_packet failed: %d", int(cerr))
		return
	}

	cerr = C.avcodec_receive_frame(ff.codecCtx, ff.frame)
	if cerr < C.int(0) { // -11
		err = fmt.Errorf("ffmpeg: avcodec_receive_frame failed: %d", int(cerr))
		return
	}
	gotframe = true

	// 解码成功.
	audioFrameAssignToAV(ff.frame, &frame)
	frame.SampleRate = self.SampleRate
	fmt.Println("ffmpeg: Decode done ", frame.SampleCount, frame.SampleRate, frame.ChannelLayout, frame.SampleFormat)
	return
}

// 解码多帧的逻辑,pkg可传多帧
func (self *AudioDecoder) DecodingMultipleFrame(pkt []byte, reSampler *Resampler) (frames []codec.AudioFrame, err error) {
	ff := &self.ff.ff
	cerr := C.wrap_avcodec_send_packet(ff.codecCtx, unsafe.Pointer(&pkt[0]), C.int(len(pkt)))
	if cerr < C.int(0) {
		if cerr == AVERROR_EOF2 {
			//
		}
		err = fmt.Errorf("ffmpeg: wrap_avcodec_send_packet failed: %d", int(cerr))
		return
	}
	frame := codec.AudioFrame{}
	for cerr >= 0 {
		cerr = C.avcodec_receive_frame(ff.codecCtx, ff.frame)
		if cerr == AVERROR_EOF2 || cerr == AvErrorEAGAIN {
			return
		} else if cerr < C.int(0) {
			err = fmt.Errorf("ffmpeg: avcodec_receive_frame failed: %d", int(cerr))
			return
		}
		audioFrameAssignToAV(ff.frame, &frame)
		frame.SampleRate = self.SampleRate
		if reSampler != nil {
			swrFrame, err1 := reSampler.Resample(frame)
			if err1 != nil {
				err = err1
				return
			}
			swrFrame.SampleRate = reSampler.OutSampleRate
			frames = append(frames, swrFrame)
			//fmt.Println("ffmpeg: Multiple Decode done ", swrFrame.SampleCount, swrFrame.SampleRate, swrFrame.ChannelLayout, swrFrame.SampleFormat)
		} else {
			frames = append(frames, frame)
			//fmt.Println("ffmpeg: Multiple Decode done ", frame.SampleCount, frame.SampleRate, frame.ChannelLayout, frame.SampleFormat)
		}
	}
	return
}

func (self *AudioDecoder) ReceiveReserved() (gotframe bool, frame codec.AudioFrame, err error) {
	ff := &self.ff.ff
	cerr := C.avcodec_receive_frame(ff.codecCtx, ff.frame)
	if cerr < C.int(0) {
		err = fmt.Errorf("ffmpeg: avcodec_receive_frame failed: %d", int(cerr))
		return
	}
	gotframe = true

	// 解码成功.
	audioFrameAssignToAV(ff.frame, &frame)
	frame.SampleRate = self.SampleRate
	fmt.Println("ffmpeg: Decode done ", frame.SampleCount, frame.SampleRate, frame.ChannelLayout, frame.SampleFormat)
	return
}

func (self *AudioDecoder) SetSampleFormat(fmt codec.SampleFormat) (err error) {
	self.SampleFormat = fmt
	return
}

func (self *AudioDecoder) SetSampleRate(rate int) (err error) {
	self.SampleRate = rate
	return
}

func (self *AudioDecoder) SetChannelLayout(ch codec.ChannelLayout) (err error) {
	self.ChannelLayout = ch
	return
}

func (self *AudioDecoder) SetBitrate(bitrate int) (err error) {
	self.Bitrate = bitrate
	return
}

func (self *AudioDecoder) Close() {
	freeFFCtx(self.ff)
}

func NewAudioDecoder(code codec.AudioCodecData) (dec *AudioDecoder, err error) {
	_dec := &AudioDecoder{}
	var id uint32

	// 解码类型.
	// TODO: 增加amr nb 和 amr wb.
	switch code.Type() {
	case codec.AAC: // aac有Extradata需要提取.
		if aaccodec, ok := code.(aacparser.CodecData); ok {
			_dec.Extradata = aaccodec.MPEG4AudioConfigBytes()
			id = C.AV_CODEC_ID_AAC
		} else {
			err = fmt.Errorf("ffmpeg: aac CodecData must be aacparser.CodecData")
			return
		}

	case codec.PCM_MULAW:
		id = C.AV_CODEC_ID_PCM_MULAW

	case codec.PCM_ALAW:
		id = C.AV_CODEC_ID_PCM_ALAW

	case codec.AMR_NB:
		id = C.AV_CODEC_ID_AMR_NB

	case codec.AMR_WB:
		id = C.AV_CODEC_ID_AMR_WB

	default:
		if ffcodec, ok := code.(audioCodecData); ok {
			_dec.Extradata = ffcodec.extradata
			id = ffcodec.codecId
		} else {
			err = fmt.Errorf("ffmpeg: invalid CodecData for ffmpeg to decode")
			return
		}
	}

	c := C.avcodec_find_decoder(id)
	if c == nil || C.avcodec_get_type(c.id) != C.AVMEDIA_TYPE_AUDIO {
		err = fmt.Errorf("ffmpeg: cannot find audio decoder id=%d", id)
		return
	}

	if _dec.ff, err = newFFCtxByCodec(c); err != nil {
		return
	}

	_dec.SampleFormat = code.SampleFormat()
	_dec.SampleRate = code.SampleRate()
	_dec.ChannelLayout = code.ChannelLayout()

	//??这里为啥wb不做初始化？？？hhl 20230607
	if id != C.AV_CODEC_ID_AMR_WB {
		if err = _dec.Setup(); err != nil {
			return
		}
	}

	dec = _dec
	return
}

func NewAudioDecoderByName(code codec.AudioCodecData) (dec *AudioDecoder, err error) {
	//这里暂时只支持amr
	_dec := &AudioDecoder{}
	var name string

	switch code.Type() {
	case codec.AMR_NB:
		name = "amrnb"
	case codec.AMR_WB:
		name = "amrwb"
	case codec.AMR_NB_OPENCORE:
		name = "libopencore_amrnb"
		//name = "amrnb"
	case codec.AMR_WB_OPENCORE:
		name = "libopencore_amrwb"
		//name = "amrwb"
	default:
		err = fmt.Errorf("ffmpeg: invalid CodecData for ffmpeg to decode")
		return
	}

	c := C.avcodec_find_decoder_by_name(C.CString(name))
	//c := C.avcodec_find_decoder(id)

	if c == nil || C.avcodec_get_type(c.id) != C.AVMEDIA_TYPE_AUDIO {
		err = fmt.Errorf("ffmpeg: cannot find audio decoder name=%v", name)
		return
	}

	if _dec.ff, err = newFFCtxByCodec(c); err != nil {
		return
	}

	_dec.SampleFormat = code.SampleFormat()
	_dec.SampleRate = code.SampleRate()
	_dec.ChannelLayout = code.ChannelLayout()

	if err = _dec.Setup(); err != nil {
		return
	}

	dec = _dec
	return
}

// NewAudioEncoderByCodecType 目前支持的encode包括aac，pcm和amr系列.
func NewAudioEncoder(code codec.AudioCodecData) (enc *AudioEncoder, err error) {

	var id uint32
	switch code.Type() {
	case codec.AAC:
		id = C.AV_CODEC_ID_AAC

	case codec.PCM_MULAW:
		id = C.AV_CODEC_ID_PCM_MULAW

	case codec.PCM_ALAW:
		id = C.AV_CODEC_ID_PCM_ALAW

	case codec.AMR_NB:
		id = C.AV_CODEC_ID_AMR_NB

	case codec.AMR_WB:
		id = C.AV_CODEC_ID_AMR_WB

	default:
		err = fmt.Errorf("ffmpeg: cannot find encoder codecType=%d", code.Type())
		return
	}

	codecDst := C.avcodec_find_encoder(id)
	if codecDst == nil || C.avcodec_get_type(id) != C.AVMEDIA_TYPE_AUDIO {
		err = fmt.Errorf("ffmpeg: cannot find audio encoder codecId=%d", id)
		return
	}

	_enc := &AudioEncoder{}
	if _enc.ff, err = newFFCtxByCodec(codecDst); err != nil {
		return
	}
	_enc.SampleFormat = code.SampleFormat()
	_enc.SampleRate = code.SampleRate()
	_enc.ChannelLayout = code.ChannelLayout()

	// TODO: 必须事先转为s16.
	if id == C.AV_CODEC_ID_AMR_WB {
		// _enc.SampleFormat = codec.S16
	}
	//if err = _enc.Setup(); err != nil {
	//	return
	//}

	enc = _enc
	return
}

func NewAudioEncoderByName(name string) (enc *AudioEncoder, err error) {
	_enc := &AudioEncoder{}

	codec := C.avcodec_find_encoder_by_name(C.CString(name))
	if codec == nil || C.avcodec_get_type(codec.id) != C.AVMEDIA_TYPE_AUDIO {
		err = fmt.Errorf("ffmpeg: cannot find audio encoder name=%s", name)
		return
	}

	if _enc.ff, err = newFFCtxByCodec(codec); err != nil {
		return
	}
	enc = _enc
	return
}

type audioCodecData struct {
	codecId       uint32
	sampleFormat  codec.SampleFormat
	channelLayout codec.ChannelLayout
	sampleRate    int
	extradata     []byte
}

func (self audioCodecData) Type() codec.CodecType {
	return codec.MakeAudioCodecType(self.codecId)
}

func (self audioCodecData) SampleRate() int {
	return self.sampleRate
}

func (self audioCodecData) SampleFormat() codec.SampleFormat {
	return self.sampleFormat
}

func (self audioCodecData) ChannelLayout() codec.ChannelLayout {
	return self.channelLayout
}

func (self audioCodecData) PacketDuration(data []byte) (dur time.Duration, err error) {
	// TODO: implement it: ffmpeg get_audio_frame_duration
	err = fmt.Errorf("ffmpeg: cannot get packet duration")
	return
}

// AVFrame to AudioFrame
func audioFrameAssignToAVParams(f *C.AVFrame, frame *codec.AudioFrame) {
	frame.SampleFormat = sampleFormatFF2AV(int32(f.format))
	frame.ChannelLayout = channelLayoutFF2AV(f.channel_layout)
	frame.SampleRate = int(f.sample_rate)
}

func audioFrameAssignToAVData(f *C.AVFrame, frame *codec.AudioFrame) {
	frame.SampleCount = int(f.nb_samples)
	frame.Data = make([][]byte, int(f.channels))
	for i := 0; i < int(f.channels); i++ {
		frame.Data[i] = C.GoBytes(unsafe.Pointer(f.data[i]), f.linesize[0])
	}
}

func audioFrameAssignToAV(f *C.AVFrame, frame *codec.AudioFrame) {
	audioFrameAssignToAVParams(f, frame)
	audioFrameAssignToAVData(f, frame)
}

// av常见操作函数.
func sampleFormatAV2FF(sampleFormat codec.SampleFormat) (ffsamplefmt int32) {
	switch sampleFormat {
	case codec.U8:
		ffsamplefmt = C.AV_SAMPLE_FMT_U8
	case codec.S16:
		ffsamplefmt = C.AV_SAMPLE_FMT_S16
	case codec.S32:
		ffsamplefmt = C.AV_SAMPLE_FMT_S32
	case codec.FLT:
		ffsamplefmt = C.AV_SAMPLE_FMT_FLT
	case codec.DBL:
		ffsamplefmt = C.AV_SAMPLE_FMT_DBL
	case codec.U8P:
		ffsamplefmt = C.AV_SAMPLE_FMT_U8P
	case codec.S16P:
		ffsamplefmt = C.AV_SAMPLE_FMT_S16P
	case codec.S32P:
		ffsamplefmt = C.AV_SAMPLE_FMT_S32P
	case codec.FLTP:
		ffsamplefmt = C.AV_SAMPLE_FMT_FLTP
	case codec.DBLP:
		ffsamplefmt = C.AV_SAMPLE_FMT_DBLP
	}
	return
}

func sampleFormatFF2AV(ffsamplefmt int32) (sampleFormat codec.SampleFormat) {
	switch ffsamplefmt {
	case C.AV_SAMPLE_FMT_U8: ///< unsigned 8 bits
		sampleFormat = codec.U8
	case C.AV_SAMPLE_FMT_S16: ///< signed 16 bits
		sampleFormat = codec.S16
	case C.AV_SAMPLE_FMT_S32: ///< signed 32 bits
		sampleFormat = codec.S32
	case C.AV_SAMPLE_FMT_FLT: ///< float
		sampleFormat = codec.FLT
	case C.AV_SAMPLE_FMT_DBL: ///< double
		sampleFormat = codec.DBL
	case C.AV_SAMPLE_FMT_U8P: ///< unsigned 8 bits, planar
		sampleFormat = codec.U8P
	case C.AV_SAMPLE_FMT_S16P: ///< signed 16 bits, planar
		sampleFormat = codec.S16P
	case C.AV_SAMPLE_FMT_S32P: ///< signed 32 bits, planar
		sampleFormat = codec.S32P
	case C.AV_SAMPLE_FMT_FLTP: ///< float, planar
		sampleFormat = codec.FLTP
	case C.AV_SAMPLE_FMT_DBLP: ///< double, planar
		sampleFormat = codec.DBLP
	}
	return
}

func channelLayoutFF2AV(layout C.uint64_t) (channelLayout codec.ChannelLayout) {
	if layout&C.AV_CH_FRONT_CENTER != 0 {
		channelLayout |= codec.CH_FRONT_CENTER
	}
	if layout&C.AV_CH_FRONT_LEFT != 0 {
		channelLayout |= codec.CH_FRONT_LEFT
	}
	if layout&C.AV_CH_FRONT_RIGHT != 0 {
		channelLayout |= codec.CH_FRONT_RIGHT
	}
	if layout&C.AV_CH_BACK_CENTER != 0 {
		channelLayout |= codec.CH_BACK_CENTER
	}
	if layout&C.AV_CH_BACK_LEFT != 0 {
		channelLayout |= codec.CH_BACK_LEFT
	}
	if layout&C.AV_CH_BACK_RIGHT != 0 {
		channelLayout |= codec.CH_BACK_RIGHT
	}
	if layout&C.AV_CH_SIDE_LEFT != 0 {
		channelLayout |= codec.CH_SIDE_LEFT
	}
	if layout&C.AV_CH_SIDE_RIGHT != 0 {
		channelLayout |= codec.CH_SIDE_RIGHT
	}
	if layout&C.AV_CH_LOW_FREQUENCY != 0 {
		channelLayout |= codec.CH_LOW_FREQ
	}
	return
}

func channelLayoutAV2FF(channelLayout codec.ChannelLayout) (layout C.uint64_t) {
	if channelLayout&codec.CH_FRONT_CENTER != 0 {
		layout |= C.AV_CH_FRONT_CENTER
	}
	if channelLayout&codec.CH_FRONT_LEFT != 0 {
		layout |= C.AV_CH_FRONT_LEFT
	}
	if channelLayout&codec.CH_FRONT_RIGHT != 0 {
		layout |= C.AV_CH_FRONT_RIGHT
	}
	if channelLayout&codec.CH_BACK_CENTER != 0 {
		layout |= C.AV_CH_BACK_CENTER
	}
	if channelLayout&codec.CH_BACK_LEFT != 0 {
		layout |= C.AV_CH_BACK_LEFT
	}
	if channelLayout&codec.CH_BACK_RIGHT != 0 {
		layout |= C.AV_CH_BACK_RIGHT
	}
	if channelLayout&codec.CH_SIDE_LEFT != 0 {
		layout |= C.AV_CH_SIDE_LEFT
	}
	if channelLayout&codec.CH_SIDE_RIGHT != 0 {
		layout |= C.AV_CH_SIDE_RIGHT
	}
	if channelLayout&codec.CH_LOW_FREQ != 0 {
		layout |= C.AV_CH_LOW_FREQUENCY
	}
	return
}

func audioFrameAssignToFFParams(frame codec.AudioFrame, f *C.AVFrame) {
	f.format = C.int(sampleFormatAV2FF(frame.SampleFormat))
	f.channel_layout = channelLayoutAV2FF(frame.ChannelLayout)
	f.sample_rate = C.int(frame.SampleRate)
	f.channels = C.int(frame.ChannelLayout.Count())
}

func audioFrameAssignToFFData(frame codec.AudioFrame, f *C.AVFrame) {
	f.nb_samples = C.int(frame.SampleCount)
	for i := range frame.Data {
		f.data[i] = (*C.uint8_t)(unsafe.Pointer(&frame.Data[i][0]))
		f.linesize[i] = C.int(len(frame.Data[i]))
	}
}

func audioFrameAssignToFF(frame codec.AudioFrame, f *C.AVFrame) {
	audioFrameAssignToFFParams(frame, f)
	audioFrameAssignToFFData(frame, f)
}
